package top.hcode.hoj.manager.oj;

import cn.hutool.core.lang.Validator;
import org.nutz.json.Json;
import org.nutz.lang.Strings;
import org.nutz.lang.Times;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import top.hcode.hoj.dao.judge.RemoteJudgeAccountEntityService;
import top.hcode.hoj.pojo.dto.VerifyRemoteJudgeAccountDTO;
import top.hcode.hoj.remoteJudge.entity.RemoteJudgeDTO;
import top.hcode.hoj.remoteJudge.entity.RemoteOjLoginDTO;
import top.hcode.hoj.remoteJudge.task.RemoteJudgeFactory;
import top.hcode.hoj.remoteJudge.task.RemoteJudgeStrategy;
import top.hcode.hoj.utils.Constants;
import top.hcode.hoj.utils.CookiesUtils;

import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author orangej
 * @since 2024/12/14
 */
@Component
public class RemoteJudgeAccountManager {
    @Autowired
    private RemoteJudgeAccountEntityService entityService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    public byte[] getLoginCaptcha(String oj, String uid) {
        RemoteJudgeStrategy judge = RemoteJudgeFactory.selectJudge(oj);
        RemoteOjLoginDTO loginDTO = judge.getLoginCaptcha();
        byte[] image = loginDTO.getCaptchaImage();

        // 保存cookie和header信息
        loginDTO.setCaptchaImage(null);
        String key = ojLoginKey(oj, uid);
        redisTemplate.opsForValue().set(key, Json.toJson(loginDTO), 600, TimeUnit.SECONDS);

        return image;
    }

    String ojLoginKey(String oj, String uid) {
        return "oj:login:" + oj + ":" + uid;
    }

    public void verifyRemoteJudgeAccount(String uid, VerifyRemoteJudgeAccountDTO verifyDTO) {
        Constants.RemoteOJ remoteOJ = Constants.RemoteOJ.getRemoteOJ(verifyDTO.getOj());
        Validator.validateNotNull(remoteOJ, "未知的oj : {}", verifyDTO.getOj());

        Map<String, String> loginCookies = null;
        if (Constants.RemoteOJ.LUOGU == remoteOJ) {
            // 有验证码的流程，从redis中获取cookie信息
            String key = ojLoginKey(verifyDTO.getOj(), uid);
            String json = redisTemplate.opsForValue().get(key);
            RemoteOjLoginDTO loginDTO = new RemoteOjLoginDTO();
            if (Strings.isNotBlank(json)) {
                loginDTO = Json.fromJson(RemoteOjLoginDTO.class, json);
            }

            loginDTO.setUsername(verifyDTO.getUsername());
            loginDTO.setPassword(verifyDTO.getPassword());
            loginDTO.setCaptchaCode(verifyDTO.getCaptcha());

            RemoteJudgeStrategy judge = RemoteJudgeFactory.selectJudge(verifyDTO.getOj());
            judge.loginWithCaptcha(loginDTO);

            loginCookies = loginDTO.getCookies();
        } else {
            // 无验证码流程
            RemoteJudgeStrategy judge = RemoteJudgeFactory.selectJudge(verifyDTO.getOj());
            RemoteJudgeDTO remoteJudgeDTO = RemoteJudgeDTO.builder().username(verifyDTO.getUsername())
                    .password(verifyDTO.getPassword()).build();
            judge.setRemoteJudgeDTO(remoteJudgeDTO);
            judge.login();

            loginCookies = CookiesUtils.toMap(remoteJudgeDTO.getCookies());
        }

        // 未抛出异常，则表示验证通过
        entityService.save(verifyDTO.getOj(), uid,
                verifyDTO.getUsername(), verifyDTO.getPassword(),
                loginCookies, Times.nextSecond(new Date(), remoteOJ.getCookieAge()));
    }
}
